﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using PluginInterface;
using Buccontrols;
using System.Runtime.InteropServices;
using Buccaneer.Types;

namespace Buccaneer
{
    public partial class PluginDaddy : Form
    {
        public PluginDaddy(PluginServices ph)
        {
            InitializeComponent();

            this.Plugins = ph;
            this.Plugins.RegisterAction(new StartDraggingAction(this));
            this.tabs = new List<PluginCouple>();
            this.afnames = new List<string>();
            this.afargs = new List<string[]>();
        }

        List<PluginCouple> tabs;
        List<string> afnames;
        List<string[]> afargs;
        DragForm dragForm;
        MdiClient mdiParentArea;
        bool handlingActRequests = false;
        IPlugin activePlugin;
        int selectedTab = 0;
        bool active;

        public PluginServices Plugins;

        public bool Active
        {
            get { return active; }
            set { this.active = value; }
        }

        public PluginCouple selectedPlugin
        {
            get
            {
                foreach (PluginCouple tab in tabs)
                {
                    try
                    {
                        if (tab.Parent.Instance.MainInterface.Name.StartsWith(this.ActiveMdiChild.Name))
                        {
                            return tab;
                        }
                    }
                    catch { continue; }
                }
                return null;
            }
        }

        #region Public Attributes

        public IPlugin ActivePlugin
        {
            get
            {
                return this.activePlugin;
            }
            set
            {
                this.activePlugin = value;
                ActivateMdiChild(value.MainInterface);
            }
        }

        #endregion

        #region Public Functions

        public void AddTab(AvailablePlugin plugin)
        {
            plugin.Instance.Daddy = this;
            plugin.Instance.MainInterface.Name = plugin.Name;
            plugin.Instance.Initialize();
            tabs.Add(new PluginCouple(selectedPlugin, plugin.Instance));
            plugin.Instance.MainInterface.Activate();
            plugin.Instance.MainInterface.Show();
            this.activePlugin = plugin.Instance;
            this.selectedTab = this.tabs.Count - 1;
        }

        public void RemoveTab(string name)
        {
            foreach (PluginCouple tab in tabs)
            {
                if (tab.Parent.Instance.MainInterface.Name == name)
                {
                    this.tabs.Remove(tab);
                    break;
                }
            }
        }

        public void AddPlugin(AvailablePlugin plugin)
        {
            if (this.ActivePlugin != null && this.ActivePlugin.MainInterface.Name.StartsWith("LoadPluginForm"))
            {
                this.ActivePlugin.MainInterface.Close();
                this.ActivePlugin.Dispose();
            }
            foreach (PluginCouple tab in tabs)
            {
                if (tab.Instance.MainInterface.Name == this.ActivePlugin.MainInterface.Name)
                {
                    plugin.Instance.Daddy = this;
                    plugin.Instance.MainInterface.Name = plugin.Name;
                    plugin.Instance.Initialize();
                    plugin.Instance.MainInterface.Show();
                    plugin.Instance.MainInterface.Activate();
                    tab.Generate(plugin.Instance);
                    this.activePlugin = plugin.Instance;
                    return;
                }
            }
            plugin.Instance.Daddy = this;
            plugin.Instance.MainInterface.Name = plugin.Name;
            plugin.Instance.Initialize();
            tabs.Add(new PluginCouple(selectedPlugin, plugin.Instance));
            plugin.Instance.MainInterface.Activate();
            plugin.Instance.MainInterface.Show();
            this.activePlugin = plugin.Instance;
            this.selectedTab = this.tabs.Count - 1;
        }

        public void RemovePlugin(string name)
        {
            foreach (Form form in this.MdiChildren)
            {
                if (form.Name == name)
                {
                    form.Close();
                    break;
                }
            }
        }

        public void ActRequest(string afname, string[] args)
        {
            this.afnames.Add(afname);
            this.afargs.Add(args);
        }

        public void HandleActRequests()
        {
            if (handlingActRequests) return;
            handlingActRequests = true;
            for (int i = 0; i < afnames.Count; i++)
            {
                Plugins.Act(afnames[i], afargs[i]);
            }
            afnames = null;
            afargs = null;
            afnames = new List<string>();
            afargs = new List<string[]>();
            handlingActRequests = false;
        }

        public PluginForm FindPluginForm(string name)
        {
            for (int i = 0; i < tabs.Count; i++)
            {
                PluginForm pf = FindPluginForm(name, tabs[i]);
                if (pf != null) return pf;
            }
            return null;
        }

        public PluginForm FindPluginForm(string name, PluginCouple pc)
        {
            if (pc.Instance.MainInterface.Name == name) 
                return pc.Instance.MainInterface;
            foreach (PluginCouple pcc in pc.Offspring)
            {
                return FindPluginForm(name, pcc);
            }
            return null;
        }

        public void StartDragging(string[] args)
        {
            string name = args[0];

            PluginForm form = FindPluginForm(name);
            if (form.Name == name)
            {
                form.SuspendLayout();
                form.Visible = false;
                form.StartPosition = FormStartPosition.Manual;
                dragForm = new DragForm(
                    new Rectangle(this.Location, this.ClientSize),
                    form.Location,
                    form.Size
                );
                dragForm.ShowDialog();
                switch (dragForm.Result)
                {
                    case DragFormResult.Return:
                        form.Location = dragForm.Location;
                        form.Size = dragForm.Size;
                        form.Visible = true;
                        form.ResumeLayout(false);
                        break;
                    case DragFormResult.Close:
                        form.Visible = true;
                        this.Plugins.Act("unloadplugin", new string[] { form.Name });
                        break;
                    case DragFormResult.Options:
                        form.Location = dragForm.Location;
                        form.Size = dragForm.Size;
                        form.Visible = true;
                        form.ResumeLayout(false);
                        break;
                    case DragFormResult.Add:
                        form.Location = dragForm.Location;
                        form.Size = dragForm.Size;
                        form.Visible = true;
                        form.ResumeLayout(false);
                        form.Activate();
                        this.Plugins.Act("addform", null);
                        break;
                    default:
                        form.Visible = true;
                        form.ResumeLayout(false);
                        break;
                }
            }
        }

        #endregion

        private void Daddy_Activated(object sender, EventArgs e)
        {
            this.active = true;
            HandleActRequests();
            setOffspringTopMost(tabs[selectedTab]);
            //this.Focus();
        }

        private void Daddy_Deactivate(object sender, System.EventArgs e)
        {
            unsetOffspringTopMost(tabs[selectedTab]);
        }

        private void setOffspringTopMost(PluginCouple pc)
        {
            if (pc.Instance.MainInterface.TopMost) return;
            pc.Instance.MainInterface.TopMost = true;
            if (pc.Offspring != null) return;
            foreach (PluginCouple pcc in pc.Offspring)
            {
                setOffspringTopMost(pcc);
            }
        }

        private void unsetOffspringTopMost(PluginCouple pc)
        {
            if (!pc.Instance.MainInterface.TopMost) return;
            pc.Instance.MainInterface.TopMost = false;
            if (pc.Offspring != null) return;
            foreach (PluginCouple pcc in pc.Offspring)
            {
                setOffspringTopMost(pcc);
            }
        }

        private void PluginDaddy_FormClosing(object sender, FormClosingEventArgs e)
        {
            foreach (Form frm in this.MdiChildren)
                frm.Close();
        }

        private void PluginDaddy_Load(object sender, EventArgs e)
        {
            try { this.Icon = Icon.ExtractAssociatedIcon(Application.StartupPath + @"\Buccaneer.exe"); } catch { }
            this.BackgroundImageLayout = ImageLayout.Stretch;
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);
        }
    }

    public class StartDraggingAction : PluginAction
    {
        public StartDraggingAction(PluginDaddy pluginDaddy)
        {
            base.name = "startdragging";
            base.func = new ActionFunction(this.StartDragging);
            base.pars.Add("formname", "the form to get started with dragging");
            base.pluginDaddy = pluginDaddy;
        }

        public void StartDragging(string[] args)
        {
            (base.pluginDaddy).StartDragging(args);
        }
    }
}
